//#define __FORCE_TRACE__
//#define __FORCE_DEBUG__
//#define __FORCE_INFO__
#define THIS_FILE "ia\fn_reinfMechanised.sqf"
#include <tmf_constants.h>
#include <tmf_macros.h>

TRACE_1("Start",_this);
TMFPROFILERSTART;

private ["_transport_type","_unit_type","_i","_roads","_completion_radius","_leader","_wp","_reinfgrp","_real_units","_side_char","_lhd","_lst","_density","_height",
		 "_helper","_best_spot","_spot","_tries1","_tries2","_start_pos","_start_unit_pos","_number_groups","_target_radius","_target_pos","_side","_debug","_reinf_lower_range","_reinf_higher_range",
		 "_reinforcement_groups","_vec_count","_vehicles","_vehiclegrp","_vec_arr","_j","_unit","_vehicle","_cdir","_wp_end"];

if !(isServer || (!isDedicated && !hasInterface)) exitWith { ERROR("Reinforcement is server or HC only!"); };

DEFAULT_PARAM(_instance_id,0,TMF_SERVER_INSTANCE_ID);
DEFAULT_PARAM(_target_pos,1,ARR_3(0,0,0));
DEFAULT_PARAM(_side,2,GVAR(SIDE_ENEMY));
DEFAULT_PARAM(_units,3,[]);
DEFAULT_PARAM(_transport_type,4,"");
DEFAULT_PARAM(_target_radius,5,200);
DEFAULT_PARAM(_start_pos,6,[]);
	
_range = ["REINF_MECHANISED_RANGE",[1000,1500]] call FFUNC(getFrameworkValue);
_reinf_timeout_delay = ["REINFORCEMENT_TIMEOUT_DELAY",600] call FFUNC(getFrameworkValue);
_side = [_side] call FFUNC(getSide);

if (count _units <= 0) then {
	_side_variable = format["INFANTRY_GROUP_%1",toUpper(str(_side))];
	_units = [_side_variable,[]] call FFUNC(getFrameworkValue);
};

_side_variable = format["LAND_TRANSPORT_%1",toUpper(str(_side))];
if (_transport_type == "" || {!isClass(configFile/"CfgVehicles"/_transport_type)}) then {
	_transport_type = [_side_variable,"I_Truck_02_covered_F"] call FFUNC(getFrameworkValue);
};
if (!isClass(configFile/"CfgVehicles"/_transport_type)) exitWith {ERROR_1("Invalid Transport Type",_transport_type);};

_vec_count = 1;
_transport_capacity = getNumber(configFile/"CfgVehicles"/_transport_type/"transportsoldier");
if (_transport_capacity < (count _units)) then {
	_vec_count = floor((count _units) / _transport_capacity) + 1;
};

if (count _units <= 0) then {
	_side_variable = format["INFANTRY_GROUP_%1",toUpper(str(_side))];
	_units = [_side_variable,[]] call FFUNC(getFrameworkValue);
};

if (_target_radius <= 30) then {
	_target_radius = 50;
};

if (!IS_ARRAY(_start_pos) || {count _start_pos < 2}) then {
	_start_pos = [];
} else {
	if (!(surfaceiswater [(_start_pos select 0), (_start_pos select 1)])) then {
		_helper = "Land_HelipadEmpty_F" createVehicleLocal [(_start_pos select 0), (_start_pos select 1), 0];
		if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
			_roads = _helper nearRoads 10;
			if (count _roads <= 0) then {
				_slope = [position _helper, 5] call FFUNC(getSlope);
				if (_slope > 0.5) then {_start_pos = [];};
			};
		} else {
			_start_pos = [];
		};
		deleteVehicle _helper;
	} else {
		_start_pos = [];
	};
};

TRACE_1("Setup", ARR_5(_transport_type,_units,_start_pos,_range,_target_pos));

_tries1 = 20;
if (count _start_pos < 3) then {
	// Used to know if a spot is good:
	// 1) The position
	// 2) The height, we want a low point
	// 3) The "density" of the spot, this is the number of player units in the vicinity modulated by their distance.
	_best_spot = [[],2000,10000000];
	_reinf_lower_range = _range select 0;
	_reinf_higher_range = _range select 1;
	_helper = "Land_HelipadEmpty_F" createVehicleLocal [0,0,0];
	while { _tries1 > 0 } do {
		_spot = [_target_pos, _reinf_higher_range, _reinf_lower_range] call FFUNC(getRanPointCircle);
		_tries2 = 40;
		_roads = [];
		// We check that we are far enough from the base and LHD.
		// If we are spawning units of our own side, this check is ignored.
		// If the target area is within the base, the check is ignored (even for enemies). Otherwise you can't make enemies attack the base :)
		if (count _spot >= 2) then {
			_roads = (_spot nearRoads 200);
		};
		while {(_tries2 > 0) && (count _roads <= 0)} do {
			_spot = [_target_pos, _reinf_higher_range, _reinf_lower_range] call FFUNC(getRanPointCircle);
			if (count _spot >= 2) then {
				_roads = (_spot nearRoads 200);
			};
			_tries2 = _tries2 - 1;
		};
		if (count _spot == 3) then {
			if (count _roads > 0) then {
				{
					_spot = (getPos _x) findEmptyPosition [0,30];
					if (count _spot == 3) exitWith {};
				} foreach _roads;
			} else {
				_spot = _spot findEmptyPosition [0,200];
			};
			if (count _spot == 3) then {
				TRACE_1("Testing spot", _spot);
				_helper setPos _spot;
				_height = (getPosASL _helper) select 2;
				if ((_height < (_best_spot select 1)) || (_height - (_best_spot select 1)) < 50) then {
					_lst = nearestObjects [_spot, ["Man","Car","Tank","Ship"], 400];
					TRACE_1("Acceptable height",ARR_2(_height,count _lst));
					_density = 0;
					{
						if ((side _x) == GVAR(side_own)) then {
							TRACE_1("Own Side",ARR_2(_x,(isplayer _x)));
							if (isplayer _x) then {
								// If a humen player is present, then we highly increase the density to reject as much as possible those spots
								_density = _density + (10000 / (_x distance _spot));
							} else {
								_density = _density + (2000 / (_x distance _spot));
							};
						};
					} foreach _lst;
					if (_density < (_best_spot select 2)) then {
						// We update the best spot
						_best_spot = [_spot, _height, _density];
						// We lower the tries count to narrow a good spot more quickly
						_tries1 = _tries1 - 1;
						TRACE_1("New best spot",ARR_2(_best_spot,_tries1));
					};
				} else {
					TRACE_1("Unacceptable height", _height);
				};
			};
		};
		_tries1 = _tries1 - 1;
	};
	deleteVehicle _helper;
	_start_pos = _best_spot select 0;
};
if (count _start_pos <= 0) exitWith {ERROR_1("Could not find a starting position", _this);};

_start_unit_pos = _start_pos;
_helper = switch (_side) do {
	case west: {"respawn_west"};
	case east: {"respawn_east"};
	case resistance: {"respawn_guerilla"};
	case civilian: {"respawn_civilian"};
	default {""};
};
if (_helper != "" && {(IS_MARKER(_helper))}) then {
	_start_unit_pos = markerPos _helper;
};

_reinfgrp = [_instance_id, _units,_side,_start_unit_pos,0] call FFUNC(spawnGroup);
_reinfgrp allowFleeing 0;
_reinfgrp setCombatMode "RED";
_reinfgrp setBehaviour "CARELESS";
_reinfgrp setSpeedMode "FULL";
TRACE_1("Created units",ARR_2(_reinfgrp, units _reinfgrp));

_vehiclegrp = [_side] call FFUNC(createGroup);
_real_units = units _reinfgrp;
_cdir = [_start_pos, _target_pos] call FFUNC(DirTo);

_fnc_damaged = {
	scriptName QUOTE(FFUNC(vehicle_handle_damage));
	TRACE_1("Start",_this);
	private ["_vehicle","_selection","_damage","_source","_projectile"];
	DEFAULT_PARAM(_vehicle,0,objNull);
	DEFAULT_PARAM(_selection,1,"");
	DEFAULT_PARAM(_damage,2,0);
	DEFAULT_PARAM(_source,3,objNUll);
	DEFAULT_PARAM(_projectile,4,"");
	if (_selection == "") then {
		if (isPlayer _source || {_damage > 0.05} || {isNull (driver _vehicle)} || {!(alive (driver _vehicle))} || !(canMove _vehicle)) then {
			[_vehicle] call FFUNC(unloadConvoy);
		};	
	};
};

_vehicles = [];
for "_i" from 1 to _vec_count do {
	_vec_arr = [_instance_id,_transport_type,_vehiclegrp,_start_pos,0,[],_cdir] call FFUNC(spawnVehicle);
	TRACE_1("Created vehicle",_vec_arr);
	_vehicle = _vec_arr select 0;
	_vehicle addEventHandler ["HandleDamage", _fnc_damaged];
	_vehicle setVariable [QGVAR(REINF_GROUP),_reinfgrp];
	_vehicles set [count _vehicles, _vehicle];
	for "_j" from 1 to _transport_capacity do {
		if (count _real_units <= 0) exitWith {};
		_unit = _real_units select 0;
		_real_units set [0,"XxDelxX"];
		_real_units = _real_units - ["XxDelxX"];
		_unit setPos (getPos _vehicle);
		_unit assignAsCargo _vehicle;
		_unit moveInCargo _vehicle;
	};
};
TRACE_1("Vehicle group",ARR_3(_vehiclegrp, count(units _vehiclegrp),_vehicles));

[_vehiclegrp] call FFUNC(deleteWaypoints);
_vehiclegrp setBehaviour "CARELESS";
_vehiclegrp setSpeedMode "NORMAL";
_vehiclegrp allowFleeing 0;
{
	if (_x == driver(vehicle _x)) then {
		_x setSkill 1;
		_x setUnitAbility 1;
	};
} foreach (units _vehiclegrp);

sleep 2;

_wp_end = _vehiclegrp addWaypoint [_target_pos, 100];
_wp_end setWaypointType "MOVE";
_wp_end setWaypointBehaviour "SAFE";
_wp_end setWaypointCompletionRadius 300;
_wp_end setWaypointFormation "FILE";
_wp_end setWaypointSpeed "NORMAL";
_wp_end setWaypointStatements ["true",format["{[(vehicle _x)] call %1;} foreach thisList;",QUOTE(FFUNC(unloadConvoy))]];

_wp = _vehiclegrp addWaypoint [(waypointPosition _wp_end), 0];
_wp setWaypointType "TR UNLOAD";
_wp setWaypointBehaviour "SAFE";
_wp setWaypointCompletionRadius 300;
_wp setWaypointFormation "FILE";
_wp setWaypointSpeed "NORMAL";
_wp setWaypointStatements ["true",format["{[(vehicle _x)] call %1;} foreach thisList;",QUOTE(FFUNC(unloadConvoy))]];
_wp setWaypointTimeout [15, 20, 25];

_wp = _vehiclegrp addWaypoint [_start_pos, 0];
_wp setWaypointType "MOVE";
_wp setWaypointBehaviour "SAFE";
_wp setWaypointCompletionRadius 300;
_wp setWaypointFormation "FILE";
_wp setWaypointSpeed "FULL";
_wp setWaypointStatements ["true",format["{[(vehicle _x)] spawn %1;} foreach thisList;",QUOTE(FFUNC(delVecCrew))]];
TRACE_1("Added waypoints",ARR_2(_vehiclegrp, waypoints _vehiclegrp));

_vehiclegrp setCurrentWaypoint _wp_end;
{
	(driver _x) setCombatMode "BLUE";
	(driver _x) setBehaviour "CARELESS";
	(driver _x) disableAI "TARGET";
	(driver _x) disableAI "AUTOTARGET";
	// (driver _x) disableAI "FSM";
	(driver _x) doMove _target_pos;
	TRACE_1("Driver",ARR_3(_x,typeof (driver _x),_target_pos));
} foreach _vehicles;

TRACE_1("End",ARR_3(_vehicles,_vehiclegrp,_reinfgrp));
TMFPROFILERSTOP;